package com.eshop.config;

import org.slf4j.LoggerFactory;
import java.util.Map;
import org.apache.commons.codec.digest.DigestUtils;
import com.alibaba.fastjson.JSON;
import java.util.HashMap;
import java.lang.reflect.Method;
import org.springframework.cache.Cache;
import org.springframework.cache.interceptor.CacheErrorHandler;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import com.alibaba.fastjson.parser.ParserConfig;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.context.annotation.Bean;
import java.time.Duration;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.slf4j.Logger;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Configuration;
import org.springframework.cache.annotation.CachingConfigurerSupport;

@Configuration(proxyBeanMethods = false)
@EnableCaching
@ConditionalOnClass({ RedisOperations.class })
@EnableConfigurationProperties({ RedisProperties.class })
public class RedisConfig extends CachingConfigurerSupport
{
    private static final Logger log;
    
    @Bean
    public RedisCacheConfiguration redisCacheConfiguration() {
        final FastJsonRedisSerializer<Object> fastJsonRedisSerializer = new FastJsonRedisSerializer<Object>(Object.class);
        RedisCacheConfiguration configuration = RedisCacheConfiguration.defaultCacheConfig();
        configuration = configuration.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer((RedisSerializer)fastJsonRedisSerializer)).entryTtl(Duration.ofHours(2L));
        return configuration;
    }
    
    @Bean(name = { "redisTemplate" })
    @ConditionalOnMissingBean(name = { "redisTemplate" })
    public RedisTemplate<Object, Object> redisTemplate(final RedisConnectionFactory redisConnectionFactory) {
        final RedisTemplate<Object, Object> template = (RedisTemplate<Object, Object>)new RedisTemplate();
        final FastJsonRedisSerializer<Object> fastJsonRedisSerializer = new FastJsonRedisSerializer<Object>(Object.class);
        template.setValueSerializer((RedisSerializer)fastJsonRedisSerializer);
        template.setHashValueSerializer((RedisSerializer)fastJsonRedisSerializer);
        ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
        template.setKeySerializer((RedisSerializer)new StringRedisSerializer());
        template.setHashKeySerializer((RedisSerializer)new StringRedisSerializer());
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }
    
    @Bean
    public KeyGenerator keyGenerator() {
        return (target, method, params) -> {
            final Map<String, Object> container = new HashMap<String, Object>(3);
            final Class<?> targetClassClass = target.getClass();
            container.put("class", targetClassClass.toGenericString());
            container.put("methodName", method.getName());
            container.put("package", targetClassClass.getPackage());
            for (int i = 0; i < params.length; ++i) {
                container.put(String.valueOf(i), params[i]);
            }
            final String jsonString = JSON.toJSONString((Object)container);
            return DigestUtils.sha256Hex(jsonString);
        };
    }
    
    @Bean
    public CacheErrorHandler errorHandler() {
        RedisConfig.log.info("初始化 -> [{}]", (Object)"Redis CacheErrorHandler");
        return (CacheErrorHandler)new CacheErrorHandler() {
            public void handleCacheGetError(final RuntimeException e, final Cache cache, final Object key) {
                RedisConfig.log.error("Redis occur handleCacheGetError：key -> [{}]", key, (Object)e);
            }
            
            public void handleCachePutError(final RuntimeException e, final Cache cache, final Object key, final Object value) {
                RedisConfig.log.error("Redis occur handleCachePutError：key -> [{}]；value -> [{}]", new Object[] { key, value, e });
            }
            
            public void handleCacheEvictError(final RuntimeException e, final Cache cache, final Object key) {
                RedisConfig.log.error("Redis occur handleCacheEvictError：key -> [{}]", key, (Object)e);
            }
            
            public void handleCacheClearError(final RuntimeException e, final Cache cache) {
                RedisConfig.log.error("Redis occur handleCacheClearError：", (Throwable)e);
            }
        };
    }
    
    static {
        log = LoggerFactory.getLogger((Class)RedisConfig.class);
    }
}
